﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GDISim._Infrastructure._Hardware._Datacenter;
using System.Xml.Serialization;
using GDISim._Infrastructure._Software._Operation;

namespace GDISim._Infrastructure._Software._Application
{
    public class Workload: ILoad
    {
        #region Members
        private DatacenterName dcName;
        private ApplicationName appName;
        private List<HourlyWorkload> hourlyWorkloadList;
        private List<OperationDistribution> operationDistributionList;
        private List<OperationFrequency> operationFrequencyList;    

        #endregion

        #region Constructor
        public Workload()
        {
        }
        #endregion

        #region Properties
        [XmlAttribute("DatacenterName")]
        public DatacenterName DcName
        {
            get
            {
                return this.dcName;
            }
            set
            {
                this.dcName = value;
            }
        }
        [XmlAttribute("ApplicationName")]
        public ApplicationName AppName
        {
            get
            {
                return this.appName;
            }
            set
            {
                this.appName = value;
            }
        }
        [XmlArray("HourlyWorkloadList"), XmlArrayItem(typeof(HourlyWorkload))]
        public List<HourlyWorkload> HourlyWorkloadList
        {
            get
            {
                return this.hourlyWorkloadList;
            }
            set
            {
                this.hourlyWorkloadList = value;
            }
        }
        [XmlArray("OperationDistributionList"), XmlArrayItem(typeof(OperationDistribution))]
        public List<OperationDistribution> OperationDistributionList
        {
            get
            {
                return this.operationDistributionList;
            }
            set
            {
                this.operationDistributionList = value;
            }
        }
        [XmlArray("OperationFrequencyList"), XmlArrayItem(typeof(OperationFrequency))]
        public List<OperationFrequency> OperationFrequencyList
        {
            get
            {
                return this.operationFrequencyList;
            }
            set
            {
                this.operationFrequencyList = value;
            }
        }
        #endregion

        #region Methods
        public List<OperationRequest> GenerateOperationRequestList()
        {
            TimeSpan startTime = new TimeSpan(0);
            Dictionary<TimeSpan, int> activityDictionary= new Dictionary<TimeSpan,int>();
            Dictionary<OperationType, double> operationDistributionDictionary= new Dictionary<OperationType,double>();
            Dictionary<OperationType, double> operationFrequencyDictionary= new Dictionary<OperationType,double>();
            List<OperationRequest> operationRequestList= new List<OperationRequest>();

            Random r = new Random();

            for (int i = 0; i < 24; i++)
            {
                for (int j = 0; j < 60; j++)
                {
                    activityDictionary.Add(startTime, r.Next(this.hourlyWorkloadList[i].Min, this.hourlyWorkloadList[i].Max));
                    startTime = startTime.Add(new TimeSpan(0, 1, 0));
                }
            }

            foreach (OperationDistribution od in this.operationDistributionList)
            {
                operationDistributionDictionary.Add(od.Operation, od.Pct);
            }
            foreach (OperationFrequency od in this.operationFrequencyList)
            {
                operationFrequencyDictionary.Add(od.Operation, od.Frequency);
            }


            foreach (TimeSpan dt in activityDictionary.Keys)
            {
                int operationNumber = activityDictionary[dt];

                foreach (OperationType ot in operationDistributionDictionary.Keys)
                {
                    double operationPct = operationDistributionDictionary[ot];
                    int otNumber = Convert.ToInt32(Math.Floor(operationPct * operationNumber));

                    for (int i = 0; i < otNumber; i++)
                    {
                        OperationRequest or = new OperationRequest();
                        or.OperationId = System.Guid.NewGuid();
                        or.OperationType = ot;
                        or.OperationTime = dt.Add(new TimeSpan(0, 0, r.Next(0, 59)));
                        operationRequestList.Add(or);
                    }

                }

            }

           operationRequestList.Sort(OperationRequest.CompareOperationRequestTimes);
           return operationRequestList; 

        }
          
        #endregion
    }
}
